package com.sp.fresh_produce.controller;

import com.sp.fresh_produce.common.GenericReturnApiObject;
import com.sp.fresh_produce.controller.dto.req.LoginRequest;
import com.sp.fresh_produce.controller.dto.req.RegisterRequest;
import com.sp.fresh_produce.controller.dto.req.UpdateSignatureRequest;
import com.sp.fresh_produce.ex.ExceptionCodeEnum;
import com.sp.fresh_produce.model.pojo.User;
import com.sp.fresh_produce.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpServletResponse;
import com.sp.fresh_produce.web.RememberMeService;

@RestController
@RequestMapping("/user")
@Tag(name = "User", description = "用户相关接口")
/**
 * 用户控制器
 * <p>
 * 提供用户领域相关的接口能力，包括：
 * - 按 ID 查询用户
 * - 统一的登录接口（支持普通/管理员登录）
 * - 兼容旧路径的管理员登录
 * - 注册用户
 * - 修改个性签名
 * - 登出
 * <p>
 * 会话与权限：
 * - 使用基类常量 {@link BaseController#USER_SESSION_KEY} 存放/读取当前登录用户对象
 * - 管理员登录通过参数 {@code admin=true} 或使用管理员专用登录路径校验
 * <p>
 * 返回值约定：统一返回 {@link com.sp.fresh_produce.common.GenericReturnApiObject}
 */
public class UserController extends BaseController {

    @Autowired
    private UserService userService;

    @Autowired
    private RememberMeService rememberMeService;

    /**
     * 按用户 ID 查询用户信息
     *
     * @param id 用户主键 ID
     * @return 对应的用户实体，找不到时由底层决定返回 null 或抛异常
     */
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Integer id) {
        return userService.getUserById(id);
    }

    /**
     * 登录（普通/管理员）
     * <p>
     * 统一的登录入口。通过查询参数 {@code admin} 控制是否校验管理员权限。
     * 登录成功后，会将用户对象放入会话，键为 {@link #USER_SESSION_KEY}。
     *
     * @param request 登录请求体（用户名、密码）
     * @param admin   是否进行管理员权限校验，默认 false
     * @param session HTTP 会话对象
     * @return 成功返回成功响应（data 为空）
     */
    @PostMapping(value = "/login", consumes = "application/json")
    @Operation(summary = "用户登录", description = "普通或管理员登录，通过 admin 参数控制是否校验管理员")
    public GenericReturnApiObject login(@Valid @RequestBody LoginRequest request,
                                        @RequestParam(defaultValue = "false") boolean admin,
                                        HttpSession session,
                                        HttpServletResponse response) {
        // 1) 调用服务进行用户名/密码认证；当 admin=true 时会额外校验管理员角色
        User user = userService.authenticate(request.getUsername(), request.getPassword(), admin);
        // 2) 认证成功，将用户放入会话用于后续接口识别登录状态
        setCurrentUser(session, user);
        // 3) 设置记住我 Cookie（默认 5 天）
        rememberMeService.onLoginSuccess(response, user.getId());
        return success();
    }

    /**
     * 注册用户
     * <p>
     * 根据用户名与密码创建新用户。用户名/密码的合法性由参数校验注解与服务层共同保证。
     *
     * @param request 注册请求体（用户名、密码）
     * @return 成功返回成功响应（data 为空）
     */
    @PostMapping("/register")
    @Operation(summary = "注册用户")
    public GenericReturnApiObject register(@Valid @RequestBody RegisterRequest request) {
        // 1) 执行注册，内部包含重名与密码非空等校验
        int result = userService.registerOrThrow(request.getUsername(), request.getPassword());
        return resultResponse(result, ExceptionCodeEnum.UNKNOWN_ERROR);
    }

    /**
     * 管理员登录（兼容旧路径）
     * <p>
     * 与统一登录逻辑一致，强制进行管理员权限校验。
     *
     * @param request 管理员登录请求体
     * @param session HTTP 会话对象
     * @return 成功返回成功响应（data 为空）
     */
    @PostMapping(value = "/admin/login", consumes = "application/json")
    @Operation(summary = "管理员登录", description = "兼容旧路径")
    public GenericReturnApiObject adminLogin(@Valid @RequestBody LoginRequest request, HttpSession session, HttpServletResponse response) {
        // 1) 旧路径的管理员登录：强制 adminRequired=true
        User user = userService.authenticate(request.getUsername(), request.getPassword(), true);
        // 2) 放入会话
        setCurrentUser(session, user);
        rememberMeService.onLoginSuccess(response, user.getId());
        return success();
    }

    /**
     * 修改个人签名
     * <p>
     * 需要已登录。对签名内容做去空格规范化后保存。
     *
     * @param request 签名更新请求体
     * @param session HTTP 会话对象，用于获取当前用户
     * @return 成功返回成功响应（data 为空）
     * @throws com.sp.fresh_produce.ex.CustomException 未登录时抛出
     */
    @PutMapping(value = "/updatePersonalizedSignature", consumes = "application/json")
    @Operation(summary = "修改个人签名")
    public GenericReturnApiObject updatePersonalizedSignature(@Valid @RequestBody UpdateSignatureRequest request,
                                                             HttpSession session) {
        // 1) 从会话读取当前登录用户
        User sessionUser = getCurrentUser(session);
        // 2) 对签名进行去空格规范化
        String normalized = request.getPersonalizedSignature() == null ? null : request.getPersonalizedSignature().trim();
        // 3) 调用领域服务更新签名（包含幂等处理）
        int updated = userService.updatePersonalizedSignature(sessionUser.getId(), normalized);
        if (updated > 0) {
            // 4) 写回最新签名到会话，保证前端读取一致
            sessionUser.setPersonalizedSignature(normalized);
            setCurrentUser(session, sessionUser);
            return success();
        }
        return fail(ExceptionCodeEnum.UNKNOWN_ERROR);
    }

    /**
     * 登出
     * <p>
     * 从会话中移除当前用户。
     *
     * @param session HTTP 会话对象
     * @return 成功响应
     */
    @PostMapping("/logout")
    @Operation(summary = "登出")
    public GenericReturnApiObject logout(HttpSession session, HttpServletResponse response) {
        // 1) 移除会话中的用户，等价于登出
        clearCurrentUser(session);
        // 2) 清除记住我 Cookie
        rememberMeService.clearRememberMe(response);
        return success();
    }
}
